package com.carrental.common.util;

public class SnowflakeIdGenerator {
    // 起始时间戳 (2020-01-01)
    private final long startTimeStamp = 1577836800000L;
    
    // 各部分占用的位数
    private final long workerIdBits = 5L;
    private final long datacenterIdBits = 5L;
    private final long sequenceBits = 12L;
    
    // 各部分最大值
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // 31
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // 31
    
    // 各部分向左的位移
    private final long workerIdShift = sequenceBits;
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    private final long timestampShift = sequenceBits + workerIdBits + datacenterIdBits;
    
    private final long workerId;
    private final long datacenterId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;
    
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        if (workerId > maxWorkerId || workerId < 0) {
            throw new IllegalArgumentException("Worker ID can't be greater than " + maxWorkerId + " or less than 0");
        }
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID can't be greater than " + maxDatacenterId + " or less than 0");
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }
    
    // 生成下一个ID
    public synchronized long nextId() {
        long currentTimestamp = timeGen();
        
        // 时钟回拨处理
        if (currentTimestamp < lastTimestamp) {
            long offset = lastTimestamp - currentTimestamp;
            if (offset <= 5) {
                try {
                    // 等待时钟追上
                    Thread.sleep(offset << 1);
                    currentTimestamp = timeGen();
                    if (currentTimestamp < lastTimestamp) {
                        throw new RuntimeException("Clock moved backwards too much");
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("Clock moved backwards", e);
                }
            } else {
                throw new RuntimeException("Clock moved backwards too much");
            }
        }
        
        // 同一毫秒内序列号递增
        if (lastTimestamp == currentTimestamp) {
            sequence = (sequence + 1) & ((1 << sequenceBits) - 1);
            if (sequence == 0) {
                // 序列号用完，等待下一毫秒
                currentTimestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 不同毫秒内序列号重置
            sequence = 0L;
        }
        
        lastTimestamp = currentTimestamp;
        
        // 组装ID
        return ((currentTimestamp - startTimeStamp) << timestampShift)
                | (datacenterId << datacenterIdShift)
                | (workerId << workerIdShift)
                | sequence;
    }
    
    // 等待下一毫秒
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }
    
    // 获取当前时间戳
    private long timeGen() {
        return System.currentTimeMillis();
    }
    
    // 使用示例
    public static void main(String[] args) {
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
        for (int i = 0; i < 10; i++) {
            System.out.println(idGenerator.nextId());
        }
    }
}